﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Text.RegularExpressions;

namespace TryTM
{
    public partial class frmMain : Form
    {
        class PartForSearch_Word
        {
            public bool Is_Negative;
            public string Word;
            public string ShowUser;
            public PartForSearch_Word(bool Is_NegativeNya, string WordNya, string ShowUserNya)
            {
                Is_Negative = Is_NegativeNya;
                Word = WordNya;
                ShowUser = ShowUserNya;
            }
        }

        class PartForSearch
        {
            List<PartForSearch_Word> CurList;

            public PartForSearch()
            {
                CurList = new List<PartForSearch_Word>();
            }

            public void Add_To_List(PartForSearch_Word AddItemNya)
            {
                CurList.Add(AddItemNya);
            }

            public string Generate_string_For_DataGrid()
            {
                string ReturnString = "";
                foreach (PartForSearch_Word CurElement in CurList)
                {
                    ReturnString = ReturnString + (ReturnString != "" ? " AND " : "") + (CurElement.Is_Negative ? "NOT(" : "") + " '" + CurElement.ShowUser + "' " +
                        (CurElement.Is_Negative ? ")" : "");
                }
                return ReturnString;
            }

            public int Get_Count()
            {
                return CurList.Count;
            }

            public PartForSearch_Word Get_At(int Index)
            {
                return CurList[Index];
            }
        }

        class RuleToSearch
        {
            List<PartForSearch> CurList;
            public RuleToSearch()
            {
                CurList = new List<PartForSearch>();
            }
            public void Add_To_List(PartForSearch AddItemNya)
            {
                CurList.Add(AddItemNya);
            }
            public void DeleteAt(int WhereDelete)
            {
                CurList.RemoveAt(WhereDelete);
            }
            public int Get_Count()
            {
                return CurList.Count;
            }
            public PartForSearch Get_At(int Index)
            {
                return CurList[Index];
            }
        }

        RuleToSearch MyKawaiiRuleToSearch;

        private void buttonAddRule_Click(object sender, EventArgs e)
        {
            // сначала надо проверить правило
            string CurWord;
            int CurLanguage = UsedLanguage.NotDetected;
            int BeforeLanguage = UsedLanguage.NotDetected;
            int CurSimbolCode = 0;
            string ShowFoeUs = ""; //что будет для поиска запихано в систему
            PartForSearch_Word CurPart;
            PartForSearch WholePart = new PartForSearch();
            for (int IND = 0; IND < dataGridViewPartOfRule.Rows.Count; IND++ )
            {
                object CurRowText = dataGridViewPartOfRule.Rows[IND].Cells["columnWord"].Value;
                if (CurRowText!= null)
                {
                    CurWord = CurRowText.ToString().Trim().ToLower();
                    
                    if (CurWord.Length == 0)
                    {
                        MessageBox.Show("Одна из строчек пуста. Заполните её, пожалуйста.");
                        return;
                    }
                    for (int JIND = 0; JIND < CurWord.Length; JIND++)
                    {
                        CurSimbolCode = (int)CurWord[JIND];
                        CurLanguage = DetectLanguage(CurSimbolCode);
                        if (CurLanguage == UsedLanguage.NotDetected)
                        {
                            MessageBox.Show("Данная поисковая система поддерживает только русский и китайский. В " + (IND + 1).ToString() +
                                " строчке " + (JIND + 1).ToString() + " символ является символом другого языка или иным символом. Исправьте, пожалуйста.");
                            return;
                        }
                        if (JIND != 0)
                        {
                            if (BeforeLanguage != CurLanguage)
                            {
                                MessageBox.Show("В " + (IND + 1).ToString() + " строчке встречаются символы разных языка. Исправьте, пожалуйста.");
                                return;
                            }
                        }
                        BeforeLanguage = CurLanguage;
                    }
                    switch (CurLanguage)
                    {
                        case UsedLanguage.Russian:
                            ShowFoeUs = CurWord;
                            /* ShowFoeUs - то, что будет для поиска запихано в систему (например, у меня - юникод,
                             * а у тебя - основа слова).
                             * CurWord - то, что пользователь увидит в запросе, отображаемом на формочку*/
                            //FIXME тут может Зализняка нужно использовать, Старостюша?
                            break;
                        case UsedLanguage.Chinese:
                            if (CurWord.Length > 1)
                            {
                                MessageBox.Show("В системе выставлено ограничение: один китайский иероглиф соответствует одному слову. " +
                                    "В " + (IND + 1).ToString() + "строчке более одного иероглифа. Исправьте, пожалуйста.");
                                return;
                            }
                            ShowFoeUs = CurSimbolCode.ToString();
                            break;
                    }
                    object BoolVal = dataGridViewPartOfRule.Rows[IND].Cells["columnIs_Negative"].Value;
                    CurPart = new PartForSearch_Word(BoolVal==null ? false : true, ShowFoeUs, CurWord);  
                    WholePart.Add_To_List(CurPart);
                }
            }
            // потом нужно уже его добавлять
            MyKawaiiRuleToSearch.Add_To_List(WholePart);
            dataGridViewSearchRule.Rows.Add();
            dataGridViewSearchRule.Rows[dataGridViewSearchRule.RowCount - 1].Cells["columnPartOfRule"].Value = WholePart.Generate_string_For_DataGrid();
            dataGridViewPartOfRule.Rows.Clear();
        }


        private void buttonDelete_Click(object sender, EventArgs e)
        {
            for (int IND = dataGridViewSearchRule.SelectedRows.Count-1; IND >= 0; IND--)
            {
                int SelRowIndex = dataGridViewSearchRule.SelectedRows[IND].Index;
                MyKawaiiRuleToSearch.DeleteAt(SelRowIndex);
                dataGridViewSearchRule.Rows.RemoveAt(SelRowIndex);
            }
        }

        private void Parametrized_Search(DataTable DataTable_TF_IDF, string Column_ID_FullPathToFile, string Column_ID_ID_Word)
        {
            //если пусто, то выделить всех
            //а вот если нет...
            int PartOfRuleCount = MyKawaiiRuleToSearch.Get_Count();
            var queryMain = (from Files in DataTable_FILES.AsEnumerable()
                             from Words in DataTable_WORDS.AsEnumerable()
                             join KeyWord in DataTable_TF_IDF.AsEnumerable()
                             on new { A = Files.Field<int>(Class_Table_FILES_Columns.ID_FullPathToFile), B = Words.Field<int>(Class_Table_WORDS_Columns.ID_Word) } equals
                             new { A = KeyWord.Field<int>(Column_ID_FullPathToFile), B = KeyWord.Field<int>(Column_ID_ID_Word) }
                             into SomeData
                             from DataNya in SomeData
                             select new
                             {
                                 FilePath = Files.Field<string>(Class_Table_FILES_Columns.FullPathToFile),
                                 Words = Words.Field<string>(Class_Table_WORDS_Columns.Word)
                             });
            var queryListMain = queryMain.ToList();
            var ResultList = (from mi in DataTable_FILES.AsEnumerable()
                              select mi.Field<string>(Class_Table_FILES_Columns.FullPathToFile)).ToList();
            if (PartOfRuleCount > 0) ResultList.Clear();
            for (int IND = 0; IND < PartOfRuleCount; IND++)
            {
                PartForSearch CurBigPart = MyKawaiiRuleToSearch.Get_At(IND);
                int PartsInParts = CurBigPart.Get_Count();
                if (PartsInParts > 0)
                {
                    PartForSearch_Word CurSmallPart = CurBigPart.Get_At(0);
                    var query = (from DataNya in queryListMain.AsEnumerable()
                                 where
                                 (from Files in queryListMain.AsEnumerable()
                                            where Files.Words == CurSmallPart.Word
                                  select Files.FilePath).Contains(DataNya.FilePath)
                                 select new
                                 {
                                     FilePath = DataNya.FilePath,
                                     Words = DataNya.Words
                                 });
                    var queryList = query.ToList();
                    if (CurSmallPart.Is_Negative)
                    {
                        var query2 = (from DataNya in queryListMain.AsEnumerable()
                                      where !(from mimi in queryList.AsEnumerable()
                                              select mimi.FilePath).Distinct().Contains(DataNya.FilePath)
                                      select new
                                      {
                                          FilePath = DataNya.FilePath,
                                          Words = DataNya.Words
                                      });
                        queryList = query2.ToList();
                    }
                    for (int JIND = 1; JIND < PartsInParts; JIND++)
                    {
                        CurSmallPart = CurBigPart.Get_At(JIND);
                        query = (from DataNya in queryList.AsEnumerable()
                                 where
                                 (from Files in queryListMain.AsEnumerable()
                                  where Files.Words == CurSmallPart.Word
                                  select Files.FilePath).Contains(DataNya.FilePath)
                                 select new
                                 {
                                     FilePath = DataNya.FilePath,
                                     Words = DataNya.Words
                                 });
                        var queryList2 = query.ToList();
                        if (CurSmallPart.Is_Negative)
                        {
                            query = (from DataNya in queryList.AsEnumerable()
                                     where !(from mimi in queryList2.AsEnumerable()
                                             select mimi.FilePath).Distinct().Contains(DataNya.FilePath)
                                     select new
                                     {
                                         FilePath = DataNya.FilePath,
                                         Words = DataNya.Words
                                     });
                            queryList2 = query.ToList();
                        }
                        queryList = queryList2;
                    }
                    //queryList - это список нужных нам файлов по "И". Теперь нужно придумать, как их прогнать по ИЛИ...
                    if (IND == 0)
                    {
                        ResultList = (from mi in queryList.AsEnumerable()
                                      select mi.FilePath).Distinct().ToList();
                    }
                    else
                    {
                        ResultList = ResultList.Union((from mi in queryList.AsEnumerable()
                                                       select mi.FilePath).Distinct().ToList()).ToList();
                    }
                }
            }
            dataGridViewSearchResults.Rows.Clear();
            foreach (string CurPath in ResultList)
            {
                dataGridViewSearchResults.Rows.Add();
                dataGridViewSearchResults.Rows[dataGridViewSearchResults.RowCount - 1].Cells["columnSearchResult"].Value = CurPath;
            }
            tabControlMain.SelectedTab = tabPageSearchResult;
        }

        private void искатьПоВсемСловамToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Parametrized_Search(DataTable_TF_IDF, Class_Table_TF_IDF_Columns.ID_FullPathToFile, Class_Table_TF_IDF_Columns.ID_Word);
        }

        private void искатьПоКлючевымСловамToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Parametrized_Search(DataTable_KeyWords, Class_Table_KeyWords_Columns.ID_FullPathToFile, Class_Table_KeyWords_Columns.ID_Word);
        }

        List<String> MySearchTemplates_FindAuthor;
        List<String> MySearchTemplates_FindUDK;
        private void Init_MySearchTemplates_FindAuthor()
        {
            MySearchTemplates_FindAuthor = new List<string>();
            MySearchTemplates_FindAuthor.Add(@"(^|\n|。|\.|;)(\ |\t)*" +
                @"(作家|笔者|[Аа]втор|[Сс]оставитель)(\ |\t)*(:|-)?(\ |\t)*(?<author>.*?)(\r|\n|\.|。|;)");
            MySearchTemplates_FindUDK = new List<string>();
            MySearchTemplates_FindUDK.Add(@"(^|\n|。|\.|;)(\ |\t)*([Уу](дк|ДК)|华联发展集团)"+
                    @"(\ |\t)*(\ |:|-)(\ |\t)*(?<udk>(\d*\.)*\d+((\ |\t)*:(\ |\t)*(\d*\.)*\d+)?)(\ |\t)*(\r|\n|\.|。|;)");
        }

        private void Add_Author(string CurAuthor, string WhatFile, DataTable DataTable_FoundAuthors)
        {
            int FileId = (from mi in DataTable_FILES.AsEnumerable()
                          where mi.Field<string>(Class_Table_FILES_Columns.FullPathToFile).Trim().ToLower() == WhatFile.Trim().ToLower()
                          select mi.Field<int>(Class_Table_FILES_Columns.ID_FullPathToFile)).ToList()[0];
            DataRow CurRow = DataTable_FoundAuthors.NewRow();
            CurRow[Class_Table_FoundAuthors_Columns.ID_FullPathToFile] = FileId;
            CurRow[Class_Table_FoundAuthors_Columns.Author] = CurAuthor.Trim().ToLower();
            if (!DataTable_FoundAuthors.AsEnumerable().Contains(CurRow))
            {
                DataTable_FoundAuthors.Rows.Add(CurRow);
            }
        }

        private void SearchAuthor(StreamReader SReader, string WhatFile)
        {
            //отлично, со словами разобрались. Самое время взяться  за поиск автора.
            SReader.BaseStream.Position = 0;
            string LineToSearchAuthor = SReader.ReadToEnd(); //считали всё в 1 строку, в лучших заветах Старостюши
            foreach (string CurTemplate in MySearchTemplates_FindAuthor)
            {
                Regex MySearchRegex = new Regex(CurTemplate);
                MatchCollection MyMatches = MySearchRegex.Matches(LineToSearchAuthor);
                int MatchCount = MyMatches.Count; 
                for (int IND = 0; IND < MatchCount; IND++)
                {
                    string CurValue = MyMatches[IND].Groups["author"].Value.Trim().ToLower();
                    if (CurValue != "")
                    {//значит, мы таки нашли что-то приличное, нужно распарсить
                        string CurAuthor="";
                        bool FirstEmpty = true;
                        for (int JIND = 0; JIND < CurValue.Length; JIND++)
                        {
                            char CurChar = CurValue[JIND];
                            switch (CurChar)
                            {
                                case ' ':
                                case '\t':
                                    if (CurAuthor != "")
                                    {
                                        if (FirstEmpty)
                                        {
                                            CurAuthor = CurAuthor + " ";
                                            FirstEmpty = false;
                                        }
                                    }
                                    break;
                                case ',':
                                case '，':
                                    Add_Author(CurAuthor, WhatFile, DataTable_FoundAuthors);
                                    FirstEmpty = true;
                                    CurAuthor = "";
                                    break;
                                default:
                                    CurAuthor = CurAuthor + CurChar;
                                    break;
                            }
                        }
                        if (CurAuthor != "") Add_Author(CurAuthor, WhatFile, DataTable_FoundAuthors);
                    }
                }
            }
        }

        private void SearchUDK(StreamReader SReader, string WhatFile)
        {
            //отлично, со словами разобрались. Самое время взяться  за поиск УДК.
            SReader.BaseStream.Position = 0;
            string LineToSearchAuthor = SReader.ReadToEnd(); //считали всё в 1 строку, в лучших заветах Старостюши
            foreach (string CurTemplate in MySearchTemplates_FindUDK)
            {
                Regex MySearchRegex = new Regex(CurTemplate);
                MatchCollection MyMatches = MySearchRegex.Matches(LineToSearchAuthor);
                int MatchCount = MyMatches.Count;
                for (int IND = 0; IND < MatchCount; IND++)
                {
                    string CurValue = MyMatches[IND].Groups["udk"].Value.Trim().ToLower();
                    if (CurValue != "")
                    {//значит, мы таки нашли что-то приличное, нужно распарсить
                        string CurAuthor = "";
                        bool FirstEmpty = true;
                        for (int JIND = 0; JIND < CurValue.Length; JIND++)
                        {
                            char CurChar = CurValue[JIND];
                            switch (CurChar)
                            {
                                case '1':
                                case '2':
                                case '3':
                                case '4':
                                case '5':
                                case '6':
                                case '7':
                                case '8':
                                case '9':
                                case '0':
                                case '.':
                                    CurAuthor = CurAuthor + CurChar;
                                    break;
                                case ':':
                                    Add_Author(CurAuthor, WhatFile, DataTable_FoundUDK);
                                    FirstEmpty = true;
                                    CurAuthor = "";
                                    break;
                                default:
                                    break;
                            }
                        }
                        if (CurAuthor != "") Add_Author(CurAuthor, WhatFile, DataTable_FoundUDK);
                    }
                }
            }
        }

        private void искатьПоАвторуToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string FindAuthor = textBoxAuthorToSearch.Text.Trim().ToLower();
            var ResultList = (from Files in DataTable_FILES.AsEnumerable()
                     join FoundAuthors in DataTable_FoundAuthors.AsEnumerable()
                     on Files.Field<int>(Class_Table_FILES_Columns.ID_FullPathToFile) equals
                     FoundAuthors.Field<int>(Class_Table_FoundAuthors_Columns.ID_FullPathToFile)
                     into SomeData
                     from DataNya in SomeData
                     where DataNya.Field<string>(Class_Table_FoundAuthors_Columns.Author) == FindAuthor
                     select Files.Field<string>(Class_Table_FILES_Columns.FullPathToFile)).Distinct();
            dataGridViewSearchResults.Rows.Clear();
            foreach (string CurPath in ResultList)
            {
                dataGridViewSearchResults.Rows.Add();
                dataGridViewSearchResults.Rows[dataGridViewSearchResults.RowCount - 1].Cells["columnSearchResult"].Value = CurPath;
            }
            tabControlMain.SelectedTab = tabPageSearchResult;
        }


        private void искатьПоУДКToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string FindAuthor = textBoxUDKToSearch.Text.Trim().ToLower();
            var ResultList = (from Files in DataTable_FILES.AsEnumerable()
                              join FoundAuthors in DataTable_FoundUDK.AsEnumerable()
                              on Files.Field<int>(Class_Table_FILES_Columns.ID_FullPathToFile) equals
                              FoundAuthors.Field<int>(Class_Table_FoundAuthors_Columns.ID_FullPathToFile)
                              into SomeData
                              from DataNya in SomeData
                              where DataNya.Field<string>(Class_Table_FoundAuthors_Columns.Author) == FindAuthor
                              select Files.Field<string>(Class_Table_FILES_Columns.FullPathToFile)).Distinct();
            dataGridViewSearchResults.Rows.Clear();
            foreach (string CurPath in ResultList)
            {
                dataGridViewSearchResults.Rows.Add();
                dataGridViewSearchResults.Rows[dataGridViewSearchResults.RowCount - 1].Cells["columnSearchResult"].Value = CurPath;
            }
            tabControlMain.SelectedTab = tabPageSearchResult;
        }
    }
}
